// ----------------------------------------------------------------------------
// singleton.h
// ----------------------------------------------------------------------------
/*
 Description:
 シングルトンオブジェクト作成用インターフェイス. 
 
 ----------------------------------------------------------------
 使い方.
 
 1. クラスのインスタンスをプログラム中で一つに限定したい場合、シングルトンクラスを継承する. 
 
 class UniqueDevice : public ::fw::Singleton< UniqueDevice >
 {
 ...
 };
 
 2. public継承した場合、任意の位置からGetInstanceメソッドで実体を参照できる. 
 
 UniqueDevice a;
 
 ...
 
 a.SomeFunction(); // OK. 
 UniqueDevice::GetInstance().SomeFunction(); // OK. 
 
 3. private継承した場合、GetInstanceメソッドによる参照は出来なくなる. 
 
 class UniqueObject : private ::fw::Singleton< UniqueObject >
 {
 ...
 };
 
 UniqueObject a;
 
 ...
 
 a.SomeFunction(); // OK. 
 UniqueObject::GetInstance().SomeFunction(); // NG. 
 
 4. RegisteredSingleton を利用した場合、RegisteredObjectの初期化時にシングルトンの
 インスタンスが作成される.
 
 RegisteredSingleton の作成は FW_REGISTER_SINGLETON マクロを利用できる. 
 第二引数でインスタンスが作成される際の優先順位を制御する. 
 
 class UniqueDevice : public Singleton<UniqueDevice>{...};
 
 FW_REGISTER_SINGLETON( UniqueDevice, priority );
 
 ここの処理を行う場合、UniqueDeviceのコンストラクタ、デストラクタは public である事. 
 
 シングルトンクラスの乱用、不適切な使用はグローバル変数の乱用と変わらないので注意する事. 
 */
#pragma once
#include <fw/base/core/macros.h>
#include <fw/base/core/assertion.h>
#include <fw/base/core/noncopyable.h>
#include <fw/base/runtime/registration_object.h>

namespace fw
{
    /**
	 * シングルトンの為のテンプレートクラス. 
	 */
	template < typename _Object > class Singleton : private NonCopyable
	{
	public:
        
		Singleton()
		{
			FW_ASSERT(s_singletonObject == 0, L"すでにインスタンスが作成されています。");
			s_singletonObject = this;
		}
        
		virtual ~Singleton()
		{
			FW_ASSERT(s_singletonObject != 0, L"破棄すべきインスタンスが存在しません。");
			s_singletonObject = 0;
		}
        
		/**
		 * シングルトンのインスタンスを取得する. 
		 * 
		 * @return シングルトンのインスタンスへの参照を返します. 
		 */
		static _Object& 				GetInstance()
		{
			FW_ASSERT(s_singletonObject != 0, L"シングルトンのインスタンスが存在しません。");
			return *(static_cast<_Object*>(s_singletonObject));
		}
        
		/**
		 * シングルトンのインスタンスが作成されているかどうかを確認する.
		 * 
		 * @return インスタンスが作成されている場合、 true を返す. 
		 */
		static bool 					IsInstanceValid()
		{
			return (s_singletonObject != 0) ? true : false;
		}
		
	private:
        
		static Singleton<_Object>*	s_singletonObject;
		
	}; /* class Singleton */

    /* テンプレートの静的メンバ変数の初期化 */
	template <typename _Object> Singleton<_Object>* Singleton<_Object>::s_singletonObject=0;

	/**
	 * RegisteredObjectによるシングルトンの為のテンプレート. 
	 */
	template< typename _Object > class RegisteredSingletonTemplate : private RegisteredObjectInterface
	{
	public:
		
		RegisteredSingletonTemplate(const char*	name, int priority)
		: RegisteredObjectInterface(name, priority)
		{
		}
		
	private:
		
		/**
		 * RegisteredObject の実体の作成.
		 * 他のファンクタと同様に登録順に生成、破棄の処理を行う.
		 * 
		 * @param operation [in]  ファンクタに対する処理.
		 */
		virtual void operator()(const RegisteredObjectInterface::ObjectOperation operation)
		{
			static _Object* s_object = 0;
			
			// TODO : コーディング規約に違反しているので、修正を検討する. 
			if( operation == FW_REGISTER_ON_INITIALIZE )
			{
				FW_ASSERT( s_object == 0, L"シングルトンの作成に失敗.\n" );
				s_object = new _Object;
			}
			else if( operation == FW_REGISTER_ON_DESTROY )
			{
				FW_ASSERT( s_object != 0, L"シングルトンの破棄に失敗.\n" );
				delete s_object;
			}
		}
		
	}; /* class RegisteredSingletonTemplate */

	/**
	 * RegisterFunction によるシングルトンの為のテンプレート.
	 * 関数による登録/破棄時の処理を記述できるので、
	 * コンストラクタ以外で初期化、破棄の処理を行う必要がある場合はこちらを利用する.
	 */
	template<typename _Singleton> class RegisteredSingletonTemplateFunction : public RegisteredObjectInterface
	{
	public:
		
		typedef void 					(_Singleton::*pFnRegisteredFunction)(ObjectOperation operation);
		
		RegisteredSingletonTemplateFunction(const char* name, pFnRegisteredFunction function, int priority)
		: RegisteredObjectInterface(name, priority)
		, m_function(function)
		{
			FW_ASSERT(0 != function);
		}
		
	private:
		
		virtual void 					operator()(ObjectOperation operation)
		{
			(Singleton<_Singleton>::GetInstance().*m_function)(operation);
		}
		
		pFnRegisteredFunction			m_function;
		
	}; /* class RegisteredSingletonTemplateFunction */
} // namespace fw 

#define FW_REGISTER_SINGLETON( _Type, _priority ) \
FW_REGISTER_OBJECT( ::fw::RegisteredSingletonTemplateFunction<_Type>, _Type, __FILE__ "(" FW_STR(__LINE__) "): " FW_STR(_Type), _priority )

//#define FW_REGISTER_SINGLETON_FUNCTION( _Singleton, _Functor, _priority ) \
//FW_REGISTER_OBJECT( ::fw::RegisteredSingletonTemplateFunction<_Singleton>, _Type, __FILE__ "(" FW_STR(__LINE__) "): " FW_STR(_Type), _Functor, _priority )
